package com.xh3140.xwidget.app.imageview;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewParent;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

@Deprecated
@SuppressWarnings("unused")
public class ScaleImageView extends View {
  private static final String TAG = ScaleImageView.class.getSimpleName();
  private static final float DEFAULT_MIN_SCALE = 1.0f;
  private static final float DEFAULT_MAX_SCALE = 5.0f;
  private final Paint mPaint;
  private final Matrix mMatrix = new Matrix();
  private final float[] mValues = new float[9];
  private final GestureDetector mGesture;
  private final ScaleGestureDetector mScaleGesture;
  private Bitmap mBitmap;
  private float mMinScale = DEFAULT_MIN_SCALE;
  private float mMaxScale = DEFAULT_MAX_SCALE;
  private float mLastMotionEventX;
  private float mLastMotionEventY;

  public ScaleImageView(@NonNull Context context) {
    this(context, null);
  }

  public ScaleImageView(@NonNull Context context, @Nullable AttributeSet attrs) {
    this(context, attrs, 0);
  }

  public ScaleImageView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    this(context, attrs, defStyleAttr, 0);
  }

  public ScaleImageView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
    mPaint = new Paint();
    mPaint.setAntiAlias(true);
    mPaint.setFilterBitmap(true);
    mPaint.setDither(true);
    mGesture = new GestureDetector(context, new OnGestureListenerImpl());
    mScaleGesture = new ScaleGestureDetector(context, new OnScaleGestureListenerImpl());
  }

  public void setImageBitmap(@Nullable Bitmap bitmap) {
    if (mBitmap != bitmap) {
      mBitmap = bitmap;
      requestLayout();
    }
  }

  public float getMinScale() {
    return mMinScale;
  }

  public void setMinScale(float minScale) {
    mMinScale = minScale;
  }

  public float getMaxScale() {
    return mMaxScale;
  }

  public void setMaxScale(float maxScale) {
    mMaxScale = maxScale;
  }

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
    int measuredWidth = widthSize;
    int measuredHeight = heightSize;
    mMatrix.getValues(mValues);
    if (widthMode == MeasureSpec.AT_MOST) {
      final float imageWidth = mValues[Matrix.MSCALE_X] * mBitmap.getWidth();
      measuredWidth = (int) (getPaddingStart() + getPaddingEnd() + imageWidth);
    }
    if (heightMode == MeasureSpec.AT_MOST) {
      final float imageHeight = mValues[Matrix.MSCALE_Y] * mBitmap.getHeight();
      measuredHeight = (int) (getPaddingTop() + getPaddingBottom() + imageHeight);
    }
    setMeasuredDimension(measuredWidth, measuredHeight);
  }

  @Override
  protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    mMatrix.reset();
    // 如果没有图片则不进行布局
    if (mBitmap == null) {
      return;
    }
    // 计算初始缩放比例
    final int width = getWidth();
    final int height = getHeight();
    final float imageWidth = mBitmap.getWidth();
    final float imageHeight = mBitmap.getHeight();
    float scale = 1f;
    // 图片的宽度超出，但高度没有超出，缩小并以宽度适应
    if (imageWidth > width && imageHeight < height) {
      scale = width / imageWidth;
    }
    // 图片的高度超出，但宽度没有超出，缩小并以高度适应
    if (imageHeight > height && imageWidth < width) {
      scale = height / imageHeight;
    }
    // 图片宽度和高度都超出或都没有超出，缩小或放大适应
    if ((imageWidth > width && imageHeight > height) || (imageWidth < width && imageHeight < height)) {
      scale = Math.min(width / imageWidth, height / imageHeight);
    }
    mMinScale = scale * DEFAULT_MIN_SCALE;
    mMaxScale = scale * DEFAULT_MAX_SCALE;
    // 变换图片矩阵
    final float centerX = imageWidth / 2f;
    final float centerY = imageHeight / 2f;
    // 以图片中心为原点缩放图片
    mMatrix.postScale(scale, scale, centerX, centerY);
    // 将缩放后的图片的中心移动到视图的中心
    mMatrix.postTranslate(getPivotX() - centerX, getPivotY() - centerY);
  }

  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (mBitmap == null) {
      return;
    }
    canvas.drawBitmap(mBitmap, mMatrix, mPaint);
  }

  private void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
    final ViewParent parent = getParent();
    if (parent != null) {
      parent.requestDisallowInterceptTouchEvent(disallowIntercept);
    }
  }

  private void dispatchScrollEvent(float distanceX, float distanceY) {
    final float[] values = new float[9];
    mMatrix.getValues(values);
    final float width = getWidth();
    final float height = getHeight();
    final float imageWidth = values[Matrix.MSCALE_X] * mBitmap.getWidth();
    final float imageHeight = values[Matrix.MSCALE_Y] * mBitmap.getHeight();
    final float left = values[Matrix.MTRANS_X];
    final float right = left + imageWidth;
    final float top = values[Matrix.MTRANS_Y];
    final float bottom = top + imageHeight;
    if (Math.abs(distanceX) > 3 * Math.abs(distanceY)) {
      if ((distanceX < 0f && right <= width) || (distanceX > 0f && left >= 0f)) {
        requestDisallowInterceptTouchEvent(false);
      }
      return;
    }
    if (Math.abs(distanceY) > 3 * Math.abs(distanceX)) {
      if ((distanceY < 0f && bottom <= height) || (distanceY > 0f && top >= 0f)) {
        requestDisallowInterceptTouchEvent(false);
      }
      return;
    }
    if (((distanceX < 0f && right <= width) || (distanceX > 0f && left >= 0f))
            && ((distanceY < 0f && bottom <= height) || (distanceY > 0f && top >= 0f))) {
      requestDisallowInterceptTouchEvent(false);
    }
  }

  @Override
  public boolean dispatchTouchEvent(@NonNull MotionEvent event) {
    if (mBitmap == null) {
      return super.dispatchTouchEvent(event);
    }
    final float x = event.getX();
    final float y = event.getY();
    switch (event.getAction()) {
      case MotionEvent.ACTION_DOWN: {
        requestDisallowInterceptTouchEvent(true);
        break;
      }
      case MotionEvent.ACTION_MOVE: {
        if (event.getPointerCount() == 1) {
          dispatchScrollEvent(x - mLastMotionEventX, y - mLastMotionEventY);
          break;
        }
      }
    }
    mLastMotionEventX = x;
    mLastMotionEventY = y;
    return super.dispatchTouchEvent(event);
  }

  @SuppressLint("ClickableViewAccessibility")
  @Override
  public boolean onTouchEvent(MotionEvent event) {
    return mGesture.onTouchEvent(event) || mScaleGesture.onTouchEvent(event);
  }

  private class OnGestureListenerImpl extends GestureDetector.SimpleOnGestureListener {
    private final float mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();

    private boolean isMoveAction(float dx, float dy) {
      return Math.sqrt(dx * dx + dy * dy) > mTouchSlop;
    }

    private boolean isMoveEnabled(float dx, float dy) {
      return Math.abs(dx) > 1.0f || Math.abs(dy) > 1.0f;
    }

    private float computeTranslateX(float distanceX, @NonNull float[] values) {
      final float width = getWidth();
      final float imageWidth = values[Matrix.MSCALE_X] * mBitmap.getWidth();
      final float left = values[Matrix.MTRANS_X];
      final float right = left + imageWidth;
      if (imageWidth <= width) {
        return getPivotX() - (left + right) / 2f;
      } else {
        if (distanceX > 0f && right - distanceX < width) {
          return width - right;
        }
        if (distanceX < 0f && left > distanceX) {
          return -left;
        }
      }
      return -distanceX;
    }

    private float computeTranslateY(float distanceY, @NonNull float[] values) {
      final float height = getHeight();
      final float imageHeight = values[Matrix.MSCALE_Y] * mBitmap.getHeight();
      final float top = values[Matrix.MTRANS_Y];
      final float bottom = top + imageHeight;
      if (imageHeight <= height) {
        return getPivotY() - (top + bottom) / 2f;
      } else {
        if (distanceY > 0f && bottom - height < distanceY) {
          return height - bottom;
        }
        if (distanceY < 0f && top > distanceY) {
          return -top;
        }
      }
      return -distanceY;
    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
      if (mBitmap == null || !isMoveAction(distanceX, distanceY)) {
        return false;
      }
      final float[] values = new float[9];
      mMatrix.getValues(values);
      final float translateX = computeTranslateX(distanceX, values);
      final float translateY = computeTranslateY(distanceY, values);
      if (isMoveEnabled(translateX, translateY)) {
        mMatrix.postTranslate(translateX, translateY);
        invalidate();
        return true;
      }
      return false;
    }
  }

  private class OnScaleGestureListenerImpl extends ScaleGestureDetector.SimpleOnScaleGestureListener {
    /**
     * 计算横向平移距离
     */
    private float computeTranslateX(@NonNull float[] values) {
      final float width = getWidth();
      final float imageWidth = values[Matrix.MSCALE_X] * mBitmap.getWidth();
      final float left = values[Matrix.MTRANS_X];
      final float right = left + imageWidth;
      if (imageWidth <= width) {
        // 图片宽度不超过视图宽度，图片横向居中
        return getPivotX() - (left + right) / 2f;
      } else {
        // 左边没有靠拢，往左移
        if (left > 0f) {
          return -left;
        }
        // 右边没有靠拢，往右移
        if (right < width) {
          return width - right;
        }
      }
      return 0f;
    }

    /**
     * 计算纵向平移距离
     */
    private float computeTranslateY(@NonNull float[] values) {
      final float height = getHeight();
      final float imageHeight = values[Matrix.MSCALE_Y] * mBitmap.getHeight();
      final float top = values[Matrix.MTRANS_Y];
      final float bottom = top + imageHeight;
      if (imageHeight <= height) {
        // 图片高度不超过视图高度，图片纵向居中
        return getPivotY() - (top + bottom) / 2f;
      } else {
        // 上边没有靠拢，往上移
        if (top > 0f) {
          return -top;
        }
        // 下边没有靠拢，往下移
        if (bottom < height) {
          return height - bottom;
        }
      }
      return 0f;
    }

    /**
     * 缩放变换后平移位置
     */
    private void translateAfterScaled() {
      final float[] values = new float[9];
      mMatrix.getValues(values);
      final float translateX = computeTranslateX(values);
      final float translateY = computeTranslateY(values);
      mMatrix.postTranslate(translateX, translateY);
    }

    @Override
    public boolean onScale(@NonNull ScaleGestureDetector detector) {
      final float[] values = new float[9];
      mMatrix.getValues(values);
      final float scale = Math.min(values[Matrix.MSCALE_X], values[Matrix.MSCALE_Y]);
      float factor = detector.getScaleFactor();
      // 可以继续缩小或者可以继续放大
      if ((factor < 1f && scale > mMinScale) || (factor > 1f && scale < mMaxScale)) {
        // 如果缩小太多则调整
        if (scale * factor < mMinScale) {
          factor = mMinScale / scale;
        }
        // 如果放大太多则调整
        if (scale * factor > mMaxScale) {
          factor = mMaxScale / scale;
        }
        mMatrix.postScale(factor, factor, detector.getFocusX(), detector.getFocusY());
        // 图片缩放后调整图片位置
        translateAfterScaled();
        invalidate();
        return true;
      }
      return false;
    }
  }
}
